package com.demo.model;

import com.demo.controller.ThreadManager;
import com.demo.draw.DrawNewCard;
import com.demo.view.MainViewPanel;

import java.util.*;

/**
 * Board model
 */
public class Board {
    /**
     * 单例模式
     */
    private static final Board instance = new Board();

    /**
     * 记录分数
     */
    private int score;

    /**
     * 画板网格行数
     */
    public static final int rows = 4;

    /**
     * 画板网格列数
     */
    public static final int cols = 4;

    /**
     * 用二维数组维护当前卡片在board的位置和它们的数字，0表示没有卡片
     */
    private int[][] grid = new int[rows][cols];

    /**
     * 用列表维护的所有卡片集合，虽然加了同步List，但遍历过程中仍需要考虑加锁
     */
    private final List<Card> cards = Collections.synchronizedList(new ArrayList<>());


    private Board() {
    }

    /**
     * add this card into the board
     * <p>
     * it will add this to list of cards and update the board with its number</p>
     * <p>
     *
     * @param card a card object to add to the board
     */
    public void add(Card card) {
        cards.add(card);
        grid[card.getRow()][card.getColumn()] = card.getNumber();
    }

    /**
     * 设置画板中的值，用于更新画板
     * <p>
     *
     * @param grid 要传入二维数组，用于更新画板
     */
    public Board setGrid(int[][] grid) {
        instance.grid = grid;
        return instance;
    }

    public Board setCards(List<Card> cards) {
        instance.cards.clear();
        instance.cards.addAll(cards);
        return instance;
    }

    public void setScore(int score) {
        this.score = score;
        MainViewPanel.getScoreView().setScore(this.score);
    }

    /**
     * @return 返回当前实例
     */
    public static Board getInstance() {
        return instance;
    }

    /**
     * 重置整个画板
     * <p>
     * 通过构造器构造新的实例
     */
    public void reset() {
        for (int i = 0; i < rows; i++) {
            Arrays.fill(grid[i], 0);
        }
        cards.clear();
        setScore(0);
    }

    public int getScore() {
        return score;
    }

    /**
     * @return 返回一个二维数组，表示当前画板的数字的值
     */
    public int[][] getGrid() {
        return instance.grid;
    }

    /**
     * @return 返回一个列表，表示当前画板拥有的卡片
     */
    public List<Card> getCards() {
        return cards;
    }

    /**
     * transform index to (row, column)
     * <p>
     *
     * @param index describing this card position
     * @return an array containing the row and column of this card
     */
    public static int[] getPosition(int index) {
        return new int[]{index / cols, index % cols};
    }

    /**
     * query where the position of specific row and column.
     * <p>
     *
     * @param row a row
     * @param col a column
     * @return the position corresponding the specific row and column.
     */
    public static int queryPosition(int row, int col) {
        return row * cols + col;
    }

    /**
     * query where the position of a card.
     * <p>
     *
     * @param card the card to query
     * @return the position of the card
     */
    public static int queryPosition(Card card) {
        return queryPosition(card.getRow(), card.getColumn());
    }

    public Board fixCards() {
        ThreadManager threadManager = ThreadManager.getInstance();
        synchronized (cards) {
            // 记录当前遍历过的卡片的位置
            Set<Integer> seen = new HashSet<>();
            Iterator<Card> it = cards.iterator();
            while (it.hasNext()) {
                Card o = it.next();
                // 位置重复
                if (!seen.add(queryPosition(o))) {
                    it.remove();
                    continue;
                }
                int number = o.getNumber();
                int curNumber = grid[o.getRow()][o.getColumn()];
                if (number != curNumber) {
                    // this is a new card
                    o.setNumber(curNumber);
                    threadManager.submit(new Thread(new DrawNewCard(o, 20)));
                }
            }
        }
        return this;
    }
}
